import json
import os

from typing import Any, AsyncIterator


from fastapi import FastAPI, Depends
from fastapi_async_sqlalchemy import SQLAlchemyMiddleware
from fastapi_pagination import add_pagination

from pydantic import BaseModel
from redis import from_url
from redis.asyncio import Redis

from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.websockets import WebSocket, WebSocketDisconnect

from common.fu_auth import FuOAuth2PasswordBearer
from common.fu_middleware import LogOperationMiddleware, JWTAuthBackend
from config import DATABASE_URL,BASE_DIR
from system.router import system_router


# from config import STATIC_URL, BASE_DIR,DEBUG_VIDEO_URL


my_oauth2_scheme = FuOAuth2PasswordBearer(tokenUrl="api/system/oauth2_login")

async def init_redis_pool(host: str, password: str, db: int = 0, port: int = 6379) -> AsyncIterator[Redis]:
    session = from_url(
        url=f"redis://{host}", port=port, password=password, db=db, encoding="utf-8", decode_responses=True)
    return session

async def lifespan_handler(app: FastAPI):
    # 启动逻辑
    session = await init_redis_pool(host="127.0.0.1", password="", db=0, port=6379)  #
    # Storing state on the app instance
    app.state.redis = session
    yield
    await session.close()

app = FastAPI(dependencies=[Depends(my_oauth2_scheme)],lifespan=lifespan_handler)



app.add_middleware(
    SQLAlchemyMiddleware,
    db_url=DATABASE_URL,
    engine_args={  # engine arguments example
        "echo": True,  # print all SQL statements
        "pool_pre_ping": True,  # feature will normally emit SQL equivalent to “SELECT 1” each time a connection is checked out from the pool
        "pool_size": 100,  # number of connections to keep open at a time
        "max_overflow": 300,  # number of connections to allow to be opened above pool_size
        "pool_recycle": 3600,
    },
)
app.add_middleware(AuthenticationMiddleware, backend=JWTAuthBackend())
app.add_middleware(LogOperationMiddleware)

add_pagination(app)
# 创建 OpenAPI 实例
app.include_router(prefix="/api", router=system_router)

# 初始化 Flasgger
# swagger = Swagger(app)

class ConnectionManager:
    def __init__(self):
        self.active_connections: list[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def send_personal_json(self, message, websocket: WebSocket):
        await websocket.send_json(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

manager = ConnectionManager()



        # await manager.broadcast(f"Client #{client_id} left the chat")

class WSRData(BaseModel):
    status: int=200
    data: Any






@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            # 接收包含文件名的 JSON 消息
            data = await websocket.receive_text()
            print(f"{client_id}: {data}")

            try:
                parsed_data = json.loads(data)
                file_name = parsed_data.get("fileName")

                if file_name:
                    file_path = os.path.join(BASE_DIR, file_name)

                    # 检查文件是否存在
                    if os.path.exists(file_path):
                        # 使用 tail_f 模拟持续读取文件内容
                        with open(file_path, "r",encoding='utf-8') as file:
                            # file.seek(0, os.SEEK_END)  # 移动到文件末尾
                            while True:
                                new_line =file.readline()
                                if new_line:
                                    await manager.send_personal_json(WSRData(status=200,data=new_line).model_dump_json(),websocket)

                    else:
                        await manager.send_personal_json(WSRData(status=200,data="文件不存在").model_dump_json(), websocket)
                else:
                    await manager.send_personal_json(WSRData(status=200,data="需要传入文件名").model_dump_json(), websocket)
            except json.JSONDecodeError:
                await manager.send_personal_json(WSRData(status=200,data="无效的json数据").model_dump_json(), websocket)

    except WebSocketDisconnect:
        manager.disconnect(websocket)
        print(f"Client #{client_id} disconnected")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)